﻿using System.ComponentModel.Composition;
using Caliburn.Micro;
using SS.WPF.Framework.BackgroundAction;
using SS.WPF.Framework.Display.Dialog;
using SS.WPF.Framework.ViewModel.Screen;

namespace SS.WPF.Framework.BusyIndicator.ViewModels
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    /// <summary>
    /// The class that is used to present a ViewModel run on background thread
    /// </summary>
    [Export(typeof(IBackgroundActionIndicatorsManager))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class BackgroundViewModel : ViewModelBase, IBackgroundActionIndicatorsManager
    {
        #region Fields

        /// <summary>
        /// The background actions
        /// </summary>
        private readonly IList<IBackgroundActionIndicator> _runningActions =
            new List<IBackgroundActionIndicator>();
        
        #endregion

        #region Implementations of IBackgroundActionIndicatorsManager

        private bool _isLoadingScreen;
        public bool IsLoadingScreen
        {
            get
            {
                return this._isLoadingScreen;
            }

            set
            {
                this._isLoadingScreen = value;
                this.NotifyOfPropertyChange(() => this.IsLoadingScreen);
            }
        }

        private IEnumerable<IBackgroundActionIndicator> _backgroundActionIndicators =
            new List<IBackgroundActionIndicator>();
        public IEnumerable<IBackgroundActionIndicator> BackgroundActionIndicators
        {
            get
            {
                return this._backgroundActionIndicators;
            }
            set
            {
                this._backgroundActionIndicators = value != null
                                                       ? new List<IBackgroundActionIndicator>(value)
                                                       : new List<IBackgroundActionIndicator>();

                this.NotifyOfPropertyChange(() => this.BackgroundActionIndicators);
                this.NotifyOfPropertyChange(() => this.HasRunningActions);
            }
        }

        public bool HasRunningActions
        {
            get
            {
                return this.BackgroundActionIndicators != null && this.BackgroundActionIndicators.Any();
            }
        }

        public void RegisterTask(IBackgroundActionIndicator action)
        {
            if (action != null)
            {
                lock (this._runningActions)
                {
                    if (!this._runningActions.Contains(action))
                    {
                        this._runningActions.Insert(0, action);
                        this.NotifyOfPropertyChange(() => this.HasRunningActions);
                        this.ShowIndicator(action).OnUIThreadAsync();
                    }
                }
                this.BackgroundActionIndicators = this._runningActions;
            }
        }

        public void UnRegisterTask(IBackgroundActionIndicator action)
        {
            if (action != null)
            {
                lock (this._runningActions)
                {
                    if (this._runningActions.Contains(action))
                    {
                        this._runningActions.Remove(action);
                        this.BackgroundActionIndicators = this._runningActions;
                    }
                }

                this.NotifyOfPropertyChange(() => this.HasRunningActions);
                var indicatorViewModel = IoC.Get<BusyIndicatorViewModel>();

                lock (indicatorViewModel)
                {
                    if (indicatorViewModel.IsShowed)
                    {
                        if (this.HasRunningActions)
                        {
                            var stop = this.BackgroundActionIndicators.All(backgroundAction => !backgroundAction.IsBlockingUI);

                            if (stop)
                            {
                                indicatorViewModel.OnStopped();
                            }
                        }
                        else
                        {
                            indicatorViewModel.OnStopped();
                        }
                    }
                }
            }
        }

        #endregion  

        #region Help Methods

        /// <summary>
        /// The show indicator.
        /// </summary>
        /// <param name="action">
        /// The action.
        /// </param>
        /// <returns>
        /// The show action
        /// </returns>
        private Action ShowIndicator(IBackgroundActionIndicator action)
        {
            return () =>
            {
                var indicatorViewModel = IoC.Get<BusyIndicatorViewModel>();

                lock (indicatorViewModel)
                {
                    if (!indicatorViewModel.IsShowed && this.HasRunningActions && action.IsBlockingUI)
                    {
                        indicatorViewModel.Title = action.Title;
                        if (action.DialogManager == null)
                        {
                            IoC.Get<IDialogManager>().ShowDialog(indicatorViewModel);
                        }
                        else
                        {
                            action.DialogManager.ShowDialog(indicatorViewModel);
                        }
                    }
                }
            };
        }

        #endregion
    }
}
